package com.campus.delivery.config;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;

/**
 * 序列换成json时,将所有的long变成string
 * 因为js中得数字类型不能包含所有的java long值
 * 不使用此转换器 long转json可能有精度问题
 */
@Configuration
public class ObjectMapperConfig {

    @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
    private String dateFormat;

    @Value("${spring.jackson.time-zone:GMT+8}")
    private String timeZone;

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        // 配置Java 8日期时间类型的序列化格式
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));
        objectMapper.registerModule(javaTimeModule);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.setDateFormat(new SimpleDateFormat(dateFormat));
        objectMapper.setTimeZone(TimeZone.getTimeZone(timeZone));

//        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// Allow field names without quotation marks （ It can be further reduced json Volume ）：
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
// Single quotation marks are allowed ：
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
// Special characters and escapes are allowed
//objectMapper.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); This is out of date .
        objectMapper.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
// allow C and C++ Style notes ：
        objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
// Serialization result format , Beautify the output 
        objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
// Enumeration output to string
//WRITE_ENUMS_USING_INDEX： Output index 
        objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
// Empty objects don't throw exceptions ：
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
//Date、Calendar A string serialized to a time format ( If you do not perform the following settings , It will be serialized into timestamp format )：
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// When deserializing , Do not throw an exception when you encounter an unknown property ：
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// When deserializing , Don't throw an exception when you encounter an ignored property ：
        objectMapper.disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);
// When deserializing , The instance property of an empty string pair is null：
        objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

        return objectMapper;
    }

}
